<?php
class XARPartitionDAO extends XARDAO{
	private static $daos = array();
	protected $partitionId = null;
	protected $tablePrefix = null;
	protected $strategy = null;
	protected $tables = array();
	
	private function __construct($modelName){		
		//load model
		$this->loader = XClassLoader::loader($modelName);
		if(!is_subclass_of($modelName, 'XARPartitionRecord')){
			throw new XORMException("class {$modelName} is not a subclass of XARPartitionRecord");
		}
		$this->annotation = XAnnotation::singleton($modelName);
		//load driver
		$driverName = $this->annotation()->get('Driver.name');
		$this->driver = XDB::singleton()->driver($driverName);		
		//load partition	
		$this->tablePrefix = $this->annotation()->get('Partition.name');
		if(is_null($this->tablePrefix)){
			throw new XORMException("class {$modelName} does not have partition name in annotation.");
		}
		$this->partitionId = $this->annotation()->get('Partition.partitionId');
		if(is_null($this->partitionId)){
			throw new XORMException("class {$modelName} does not have partition id in annotation.");
		}
	}
	
	/**
	 * @return XARPartitionDAO
	 */	
	public static function dao($model){
		if (!isset(self::$daos[$model])) {
			self::$daos[$model] = new self($model);
		}
		return self::$daos[$model];
	}
	
	public function partitionId(){
		return $this->partitionId;
	}
	
	/**
	 * @return XPartitionStrategy
	 */		
	public function strategy(){
		//lazy load. should not be called if user realize partition logic in record class  
		if(is_null($this->strategy)){
			$this->_loadStrategy();
		}
		return $this->strategy;
	}
	
	protected function _loadStrategy(){
		//load strategy
		$strategyName = $this->annotation()->get('Strategy.name');
		if(is_null($strategyName)){
			throw new XORMException("class {$this->loader->name()} does not have partition strategy definition in annotations.");
		}
		$class = 'X'.x_name_to_java($strategyName).'PartitionStrategy';		
		if(!XClassLoader::loader($class)->isSubclassOf('XPartitionStrategy')){
			throw new XORMException("class {$class} must implement XPartitionStrategy");
		}
		$this->strategy = XFactory::singleton()->get($class);
	}
	
	public function insert(XModel $model, array $params = array()){
		$this->loadTable($model, $params);
		return parent::insert($model, $params);
	}
	
	public function update(XModel $model, array $params = array()){
		$this->loadTable($model, $params);
		return parent::update($model, $params);
	}

	public function remove(XModel $model, array $params = array()){
		$this->loadTable($model, $params);
		return parent::remove($model, $params);
	}
	
	/**
	 * @return XPartitionTable
	 */	
	public function loadTable(XModel $model, array $params = array()){
		$pid = $this->partitionId;
		$value = $model->$pid;
		if(is_null($value)){
			if(!isset($params[$pid])){				
				throw new XORMException("class {$this->loader->name()} should have a valid partition id.");
			}
			$value = $params[$pid];
		}
		$this->table = $this->loadTableByPartitionId($value);
		return $this->table;
	}
	
	/**
	 * @return XPartitionTable
	 */	
	public function loadTableByPartitionId($value){
		$model = XFactory::singleton()->get($this->loader->name());
		$tableName = $model->partition($this->annotation(), $value);
		$this->table = $this->loadTableByPartitionName($tableName);
		return $this->table;
	}
	
	/**
	 * @return XPartitionTable
	 */	
	public function loadTableByPartitionName($tableName){
		if(isset($this->tables[$tableName])){
			$this->table = $this->tables[$tableName];
			return $this->table;
		}
		$this->table = new XPartitionTable($this->driver()->loadTable($tableName));
		$this->table->setpartitionID($this->partitionId());
		$this->table->validate();
		$this->tables[$tableName] = $this->table;
		return $this->table;
	}
	
	public function allPartitions(){		
		$model = XFactory::singleton()->get($this->loader->name());
		return $model->allPartitions($this->annotation());		
	}
	
	public function uniqueId(){
		return $this->partitionId();
	}
	
	public function defaultForeignKey(){
		return x_name_to_c($this->tablePrefix).'_id';
	}
		
}
?>